package com.moli.iov.alarm.service.stat;

import com.moli.iov.alarm.enums.AlarmReportTypeEnum;
import com.moli.iov.alarm.model.dto.req.StatAlarmParamDto;
import com.moli.iov.alarm.model.dto.res.*;
import com.moli.iov.base.model.po.VehicleBase;
import com.moli.iov.base.remote.IVehicleBaseRemoteService;
import com.moli.iov.handle.alarm.enums.AlarmCategoryEnum;
import com.moli.iov.handle.alarm.enums.AlarmCodeEnum;
import com.moli.iov.handle.alarm.enums.AlarmLevelEnum;
import com.moli.iov.handle.alarm.enums.AlarmStatusEnum;
import com.moli.iov.rest.RestResponse;
import com.moli.iov.util.DateUtil;
import com.moli.iov.util.JsonUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;

public class AlarmStatDetailFactory {

    Map<String, Object> result;

    List<AlarmInfoResDto> alarmInfoResDtos;

    List<String> dateList = new ArrayList<>();

    public AlarmStatDetailFactory(List<AlarmInfoResDto> alarmInfoResDtos) {
        this.alarmInfoResDtos = alarmInfoResDtos;
        result = new HashMap<>();
    }

    public AlarmStatDetailFactory setVehicleTypes(IVehicleBaseRemoteService vehicleBaseRemoteService, StatAlarmParamDto dto) {

        if (dto == null || dto.getReportTypeList() == null || !dto.getReportTypeList().contains(AlarmReportTypeEnum.VEHICLE_TYPE.getFlag())) {
            return this;
        }

        List<String> vinList = new ArrayList<>();
        for (AlarmInfoResDto alarmInfoResDto : alarmInfoResDtos) {
            if (alarmInfoResDto != null && !StringUtils.isEmpty(alarmInfoResDto.getVin())) {
                vinList.add(alarmInfoResDto.getVin());
            }
        }

        RestResponse<Map<String, VehicleBase>> res = vehicleBaseRemoteService.listVehicleBaseByVin(vinList);

        Map<String, String> map = new HashMap<>();
        if (res != null && res.flag && res.getData().size() > 0) {
            for (VehicleBase value : res.getData().values()) {
                if (value != null
                        && !StringUtils.isEmpty(value.getVin())
                        && !StringUtils.isEmpty(value.getBrandName())
                        && !StringUtils.isEmpty(value.getVehicleSeriesName())
                        && !StringUtils.isEmpty(value.getVehicleTypeName())) {
                    map.put(value.getVin(), value.getBrandName() + value.getVehicleSeriesName() + value.getVehicleTypeName());
                }
            }
        }

        int totalCount = alarmInfoResDtos.size();

        Map<String, Integer> countMap = new HashMap<>();

        for (AlarmInfoResDto alarmInfoResDto : alarmInfoResDtos) {
            if (alarmInfoResDto != null && !StringUtils.isEmpty(alarmInfoResDto.getVin())) {
                String vehicleType = map.get(alarmInfoResDto.getVin());
                if (!StringUtils.isEmpty(vehicleType)) {
                    Integer count = countMap.get(vehicleType);
                    if (count == null) {
                        countMap.put(vehicleType, 1);
                    } else {
                        countMap.put(vehicleType, count + 1);
                    }
                } else {
                    Integer count = countMap.get("其他");
                    if (count == null) {
                        countMap.put("其他", 1);
                    } else {
                        countMap.put("其他", count + 1);
                    }
                }
            }
        }

        List<StatAlarmTypeDetailDto> list = new ArrayList<>();
        for (Map.Entry<String, Integer> entry : countMap.entrySet()) {
            StatAlarmTypeDetailDto detailDto = new StatAlarmTypeDetailDto();
            detailDto.setTypeCount(entry.getValue());
            detailDto.setTypeName(entry.getKey());
            detailDto.setTypeRadio(getRatio(entry.getValue(), totalCount));
            list.add(detailDto);
        }

        AlarmInfoChatDto alarmInfoChatDto = new AlarmInfoChatDto();
        alarmInfoChatDto.setList(list);
//        Map<String, String> fieldMap = new HashMap<>();
//        fieldMap.put("typeCount","报警数量");
//        fieldMap.put("typeName","车型");
//        fieldMap.put("typeRadio","占比");
//        alarmInfoChatDto.setFieldMap(fieldMap);
        List<FieldDto> fieldMap = new ArrayList<>();
        fieldMap.add(new FieldDto("typeName", "车型"));
        fieldMap.add(new FieldDto("typeCount", "数量"));
        fieldMap.add(new FieldDto("typeRadio", "占比"));
        alarmInfoChatDto.setFieldMap(fieldMap);
        result.put(AlarmReportTypeEnum.VEHICLE_TYPE.getFlag() + "", alarmInfoChatDto);

        return this;
    }

    public void setDateList(StatAlarmParamDto dto) {
        Long timer = 86400000L;
        int i = 0;
        if(dto.getBeginTime()!=null && dto.getEndTime()!=null){
            while (i * timer + dto.getBeginTime().getTime() <= dto.getEndTime().getTime()) {
                String date = DateUtil.format(DateUtil.YEAR_DAY, new Date(i * timer + dto.getBeginTime().getTime()));
                dateList.add(date);
                i++;
            }
        }
    }

    public Map<String, Object> getMap(StatAlarmParamDto dto) {
        setDateList(dto);
        List<Integer> reportTypeList = dto.getReportTypeList();
        for (Integer flag : reportTypeList) {
            switch (AlarmReportTypeEnum.getEnum(flag)) {
                case ALARM_COUNT: //报警数量
                    if (dto.getReportCategory() <= 2) {
                        setAlarmCount(AlarmCategoryEnum.getEnum(dto.getAlarmCategory()));
                    } else {
                        setAlarmCountLine(AlarmCategoryEnum.getEnum(dto.getAlarmCategory()));
                    }
                    break;
                case ALARM_STATUS:
                    setAlarmStatus();
                    break;
                case VEHICLE_TYPE:
//                    setVehicleType();
                    break;
                case ADD_ALARM_COUNT:
                    setAddAlarmCount();
                    break;
                case REMOVE_ALARM_COUNT:
                    setRemoveAlarmCount();
                    break;
                default:
            }
        }
        return result;
    }


    private void setAddAlarmCount() {
        Map<String, Integer> map = new HashMap<>();

        List<StatAlarmDateDetailDto> list = new ArrayList<>();

        int totalCount = 0;
        for (AlarmInfoResDto dto : alarmInfoResDtos) {
            String dateStr = DateUtil.format(DateUtil.YEAR_DAY, dto.getBeginTime());
            Integer count = map.get(dateStr);
            if (count == null) {
                map.put(dateStr, 1);
            } else {
                map.put(dateStr, count + 1);
            }
            totalCount++;
        }

        if(dateList.size()<=0){
            if(alarmInfoResDtos!=null && alarmInfoResDtos.size()>0){
                AlarmInfoResDto beginDto = alarmInfoResDtos.get(alarmInfoResDtos.size()-1);
                AlarmInfoResDto endDto = alarmInfoResDtos.get(0);
                if(beginDto!=null && beginDto.getBeginTime()!=null
                    && endDto!=null && endDto.getBeginTime()!=null){
                    StatAlarmParamDto param = new StatAlarmParamDto();
                    param.setBeginTime(beginDto.getBeginTime());
                    param.setEndTime(endDto.getBeginTime());
                    setDateList(param);
                }
            }
        }

        if(dateList.size()>0){
            for (String date : dateList) {
                StatAlarmDateDetailDto e = new StatAlarmDateDetailDto();
                Integer val = map.get(date)==null?0:map.get(date);
                e.setDate(date);
                e.setAlarmCount(val);
                e.setAlarmRadio(getRatio(val, totalCount));
                list.add(e);
            }
        }


//        for (Map.Entry<String, Integer> entry : map.entrySet()) {
//            StatAlarmDateDetailDto e = new StatAlarmDateDetailDto();
//            e.setAlarmCount(entry.getValue());
//            e.setDate(entry.getKey());
//            e.setAlarmRadio(getRatio(entry.getValue(), totalCount));
//            list.add(e);
//        }

        AlarmInfoChatDto alarmInfoChatDto = new AlarmInfoChatDto();
        alarmInfoChatDto.setList(list);
        List<FieldDto> fieldMap = new ArrayList<>();
        fieldMap.add(new FieldDto("date", "日期"));
        fieldMap.add(new FieldDto("alarmCount", "新增数量"));
        fieldMap.add(new FieldDto("alarmRadio", "占比"));
        alarmInfoChatDto.setFieldMap(fieldMap);
        result.put(AlarmReportTypeEnum.ADD_ALARM_COUNT.getFlag() + "", alarmInfoChatDto);

    }

    private void setRemoveAlarmCount() {
        Map<String, Integer> map = new HashMap<>();

        List<StatAlarmDateDetailDto> list = new ArrayList<>();

        int totalCount = 0;
        for (AlarmInfoResDto dto : alarmInfoResDtos) {
            String dateStr = DateUtil.format(DateUtil.YEAR_DAY, dto.getEndTime());
            if (dto.getStatus() != null) {
                if (dto.getStatus() == AlarmStatusEnum.ALARM_END.getFlag()) {
                    Integer count = map.get(dateStr);
                    if (count == null) {
                        map.put(dateStr, 1);
                    } else {
                        map.put(dateStr, count + 1);
                    }
                    totalCount++;
                }
            }
        }

        if(dateList.size()<=0){
            if(alarmInfoResDtos!=null && alarmInfoResDtos.size()>0){
                AlarmInfoResDto beginDto = alarmInfoResDtos.get(alarmInfoResDtos.size()-1);
                AlarmInfoResDto endDto = alarmInfoResDtos.get(0);
                if(beginDto!=null && beginDto.getBeginTime()!=null
                        && endDto!=null && endDto.getBeginTime()!=null){
                    StatAlarmParamDto param = new StatAlarmParamDto();
                    param.setBeginTime(beginDto.getBeginTime());
                    param.setEndTime(endDto.getBeginTime());
                    setDateList(param);
                }
            }
        }
        if(dateList.size()>0){
            for (String date : dateList) {
                StatAlarmDateDetailDto e = new StatAlarmDateDetailDto();
                Integer val = map.get(date)==null?0:map.get(date);
                e.setDate(date);
                e.setAlarmCount(val);
                e.setAlarmRadio(getRatio(val, totalCount));
                list.add(e);
            }
        }

//        for (Map.Entry<String, Integer> entry : map.entrySet()) {
//            StatAlarmDateDetailDto e = new StatAlarmDateDetailDto();
//            e.setAlarmCount(entry.getValue());
//            e.setDate(entry.getKey());
//            e.setAlarmRadio(getRatio(entry.getValue(), totalCount));
//            list.add(e);
//        }
        AlarmInfoChatDto alarmInfoChatDto = new AlarmInfoChatDto();
        alarmInfoChatDto.setList(list);
        List<FieldDto> fieldMap = new ArrayList<>();
        fieldMap.add(new FieldDto("date", "日期"));
        fieldMap.add(new FieldDto("alarmCount", "解除数量"));
        fieldMap.add(new FieldDto("alarmRadio", "占比"));

        alarmInfoChatDto.setFieldMap(fieldMap);
        result.put(AlarmReportTypeEnum.REMOVE_ALARM_COUNT.getFlag() + "", alarmInfoChatDto);

    }


    private String getRatio(Integer numerator, Integer denominator) {
        if (numerator != null && denominator != null && denominator != 0) {
            Double f1 = Double.valueOf(numerator)  / Double.valueOf(denominator) * 100;
            String res = new BigDecimal(f1).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
            return res + "%";
        }
        return "0%";
    }

    private void setAlarmStatus() {
        Set<Integer> codeSet = AlarmStatusEnum.getAlarmStatus();

        Map<Integer, Integer> map = new HashMap<>();
        for (Integer code : codeSet) {
            map.put(code, 0);
        }

        int totalCount = 0;
        for (AlarmInfoResDto dto : alarmInfoResDtos) {
            Integer code = dto.getStatus();
            if (codeSet.contains(code)) {
                Integer count = map.get(code);
                map.put(code, count + 1);
                totalCount++;
//            }
            } else if (code.equals(AlarmStatusEnum.IGNORE.getFlag())) { //忽略报警算入报警中
                Integer count = map.get(AlarmStatusEnum.ALARMING.getFlag());
                map.put(AlarmStatusEnum.ALARMING.getFlag(), count + 1);
                totalCount++;
            }
        }

        List<StatAlarmTypeDetailDto> list = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            StatAlarmTypeDetailDto detailDto = new StatAlarmTypeDetailDto();
            detailDto.setTypeName(AlarmStatusEnum.getMsg(entry.getKey()));
            detailDto.setTypeCount(entry.getValue());
            detailDto.setTypeRadio(getRatio(entry.getValue(), totalCount));

            list.add(detailDto);
        }

        AlarmInfoChatDto alarmInfoChatDto = new AlarmInfoChatDto();
        alarmInfoChatDto.setList(list);
//        Map<String, String> fieldMap = new HashMap<>();
//        fieldMap.put("typeCount","数量");
//        fieldMap.put("typeName","报警项目");
//        fieldMap.put("typeRadio","占比");
//        alarmInfoChatDto.setFieldMap(fieldMap);
        List<FieldDto> fieldMap = new ArrayList<>();
        fieldMap.add(new FieldDto("typeName", "报警项目"));
        fieldMap.add(new FieldDto("typeCount", "数量"));
        fieldMap.add(new FieldDto("typeRadio", "占比"));
        alarmInfoChatDto.setFieldMap(fieldMap);
        result.put(AlarmReportTypeEnum.ALARM_STATUS.getFlag() + "", alarmInfoChatDto);

    }


    private void setAlarmCountLine(AlarmCategoryEnum e) {

        //获取报警类型
        Set<Integer> alarmCodes = null;
        if (e == AlarmCategoryEnum.RISK_OFFLINE_ALARM || e == AlarmCategoryEnum.FENCE_ALARM) {
            alarmCodes = AlarmCategoryEnum.getAlarmCodes(e.getFlag());
        } else {
            alarmCodes = AlarmLevelEnum.getLevels();
        }

        List<Map<String, String>> list = new ArrayList<>();

        // key: 日期 value-key:报警类型 value-value:报警数量
        Map<String, Map<Integer, Integer>> map = new HashMap<>();

        List<Integer> codeList = new ArrayList<>();
        for (AlarmInfoResDto dto : alarmInfoResDtos) {
            Integer code = dto.getAlarmCode();
            if (e == AlarmCategoryEnum.DEVICE_ALARM) {
                code = dto.getAlarmLevel();
            }

            String dateStr = DateUtil.format(DateUtil.YEAR_DAY, dto.getBeginTime());
            Map<Integer, Integer> tmpMap = map.get(dateStr);
            if (tmpMap == null) {
                tmpMap = getCodeCountMap(e);
            } else {
                Integer count = tmpMap.get(code);
                if (count == null) {
                    tmpMap.put(code, 1);
                } else {
                    tmpMap.put(code, count + 1);
                }
            }
            map.put(dateStr, tmpMap);
        }

        AlarmInfoChatDto alarmInfoChatDto = new AlarmInfoChatDto();

        Map<String, String> fieldMap = new HashMap<>();

        for (String date : dateList) {
            Map<String, String> entryMap = new HashMap<>();
            entryMap.put("date", date);
            Map<Integer, Integer> val = map.get(date);
            if (val == null) {
                val = new HashMap<>();
            }

            switch (e) {
                case DEVICE_ALARM:
                    for (Integer lvl : AlarmLevelEnum.getLevels()) {
                        Integer count = val.get(lvl);
                        entryMap.put(getTypeName(lvl, e), count == null ? "0" : count.toString());
                    }
                    break;
                case RISK_OFFLINE_ALARM:
//                    int mileageExceptionChangeCode = AlarmCodeEnum.MILEAGE_EXCEPTION_CHANGE.getFlag();
//                    Integer mileageExceptionChangeCount = val.get(mileageExceptionChangeCode);
//                    entryMap.put(getTypeName(mileageExceptionChangeCode, e), mileageExceptionChangeCount == null ? "0" : mileageExceptionChangeCount.toString());

                    int offLineCode = AlarmCodeEnum.OFF_LINE.getFlag();
                    Integer offLineCount = val.get(offLineCode);
                    entryMap.put(getTypeName(offLineCode, e), offLineCount == null ? "0" : offLineCount.toString());
                    break;
                case FENCE_ALARM:
                    int outFenceCode = AlarmCodeEnum.OUT_FENCE.getFlag();
                    Integer outFenceCount = val.get(outFenceCode);
                    entryMap.put(getTypeName(outFenceCode, e), outFenceCount == null ? "0" : outFenceCount.toString());

                    int inFenceCode = AlarmCodeEnum.OUT_FENCE.getFlag();
                    Integer inFenceCount = val.get(inFenceCode);
                    entryMap.put(getTypeName(inFenceCode, e), inFenceCount == null ? "0" : inFenceCount.toString());
                    break;
                default:
            }
            list.add(entryMap);
        }
//        for (Map.Entry<String, Map<Integer, Integer>> entry : map.entrySet()) {
//            Map<String, String> entryMap = new HashMap<>();
//            entryMap.put("date", entry.getKey());
//            for (Map.Entry<Integer, Integer> entryValue : entry.getValue().entrySet()) {
//                String field = getTypeName(entryValue.getKey(), e);
//                entryMap.put(field, entryValue.getValue() + "");
////                fieldMap.put(field,getFieldName(field));
//            }
//            list.add(entryMap);
//        }

        alarmInfoChatDto.setList(list);
//        fieldMap.put("date","日期");
        alarmInfoChatDto.setFieldMap(getFieldMap(e));
        result.put(AlarmReportTypeEnum.ALARM_COUNT.getFlag() + "", alarmInfoChatDto);
    }

    private List<FieldDto> getFieldMap(AlarmCategoryEnum e) {
        List<FieldDto> list = new ArrayList<>();
        list.add(new FieldDto("date", "日期"));
        switch (e) {
            case FENCE_ALARM:
                list.add(new FieldDto("outFence", AlarmCodeEnum.OUT_FENCE.getMsg()));
                list.add(new FieldDto("inFence", AlarmCodeEnum.IN_FENCE.getMsg()));
                break;
            case DEVICE_ALARM:
                list.add(new FieldDto("oneLevel", AlarmLevelEnum.ONE.getMsg()));
                list.add(new FieldDto("twoLevel", AlarmLevelEnum.PLATFORM.getMsg()));
                list.add(new FieldDto("threeLevel", AlarmLevelEnum.THREE.getMsg()));
                break;
            case RISK_OFFLINE_ALARM:
                list.add(new FieldDto("offLine", AlarmCodeEnum.OFF_LINE.getMsg()));
               // list.add(new FieldDto("mileageExceptionChange", AlarmCodeEnum.MILEAGE_EXCEPTION_CHANGE.getMsg()));
                break;
            default:
        }
        return list;
    }


    private Map<Integer, Integer> getCodeCountMap(AlarmCategoryEnum e) {
        Map<Integer, Integer> map = new HashMap<>();
        switch (e) {
            case FENCE_ALARM:
                map.put(AlarmCodeEnum.IN_FENCE.getFlag(), 0);
                map.put(AlarmCodeEnum.OUT_FENCE.getFlag(), 0);
                break;
            case DEVICE_ALARM:
                map.put(AlarmLevelEnum.ONE.getFlag(), 0);
                map.put(AlarmLevelEnum.PLATFORM.getFlag(), 0);
                map.put(AlarmLevelEnum.THREE.getFlag(), 0);
                break;
            case RISK_OFFLINE_ALARM:
                map.put(AlarmCodeEnum.OFF_LINE.getFlag(), 0);
                //map.put(AlarmCodeEnum.MILEAGE_EXCEPTION_CHANGE.getFlag(), 0);
                break;
            default:
        }
        return map;
    }


    public static String getFieldName(String field) {
        switch (field) {
            case "outFence":
                return "出围栏";
            case "inFence":
                return "进围栏";
            case "mileageExceptionChange":
                return "里程异变";
            case "offLine":
                return "失联报警";
            case "oneLevel":
                return "一级报警";
            case "twoLevel":
                return "二级报警";
            case "threeLevel":
                return "三级报警";
            default:
        }
        return null;
    }

    public static String getTypeName(Integer key, AlarmCategoryEnum e) {
        if (e == AlarmCategoryEnum.RISK_OFFLINE_ALARM || e == AlarmCategoryEnum.FENCE_ALARM) {
            switch (AlarmCodeEnum.getEnum(key)) {
                case OUT_FENCE:
                    return "outFence";
                case IN_FENCE:
                    return "inFence";
                case MILEAGE_EXCEPTION_CHANGE:
                    return "mileageExceptionChange";
                case OFF_LINE:
                    return "offLine";
                default:
            }
        } else {
            switch (AlarmLevelEnum.getEnum(key)) {
                case ONE:
                    return "oneLevel";
                case PLATFORM:
                    return "twoLevel";
                case THREE:
                    return "threeLevel";
                default:
            }
        }
        return null;
    }


    private void setAlarmCount(AlarmCategoryEnum e) {
        Set<Integer> alarmCodes = null;
        if (e == AlarmCategoryEnum.RISK_OFFLINE_ALARM || e == AlarmCategoryEnum.FENCE_ALARM) {
            alarmCodes = AlarmCategoryEnum.getAlarmCodes(e.getFlag());
        } else {
            alarmCodes = AlarmLevelEnum.getLevels();
        }

        Map<Integer, Integer> map = new HashMap<>();
        for (Integer alarmCode : alarmCodes) {
            map.put(alarmCode, 0);
        }

        int totalCount = 0;
        for (AlarmInfoResDto dto : alarmInfoResDtos) {
            Integer alarmCode = dto.getAlarmCode();
            if (e == AlarmCategoryEnum.DEVICE_ALARM) {
                alarmCode = dto.getAlarmLevel();
            }

            if (alarmCodes.contains(alarmCode)) {
                Integer count = map.get(alarmCode);
                map.put(alarmCode, count + 1);
                totalCount++;
            }
        }

        List<StatAlarmTypeDetailDto> list = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            StatAlarmTypeDetailDto detailDto = new StatAlarmTypeDetailDto();
            detailDto.setTypeName(getTypeName(e, entry.getKey()));
            detailDto.setTypeCount(entry.getValue());
            detailDto.setTypeRadio(getRatio(entry.getValue(), totalCount));

            list.add(detailDto);
        }

        AlarmInfoChatDto alarmInfoChatDto = new AlarmInfoChatDto();
        alarmInfoChatDto.setList(list);
//        Map<String, String> fieldMap = new HashMap<>();
//        fieldMap.put("typeCount","数量");
//        fieldMap.put("typeName","报警项目");
//        fieldMap.put("typeRadio","占比");
        List<FieldDto> fieldMap = new ArrayList<>();
        fieldMap.add(new FieldDto("typeName", "报警项目"));
        fieldMap.add(new FieldDto("typeCount", "数量"));
        fieldMap.add(new FieldDto("typeRadio", "占比"));
        alarmInfoChatDto.setFieldMap(fieldMap);
        result.put(AlarmReportTypeEnum.ALARM_COUNT.getFlag() + "", alarmInfoChatDto);
    }

    public static String getTypeName(AlarmCategoryEnum e, Integer i) {
        switch (e) {
            case RISK_OFFLINE_ALARM:
            case FENCE_ALARM:
                return AlarmCodeEnum.getMsg(i);
            case DEVICE_ALARM:
                return AlarmLevelEnum.getMsg(i);
            default:
        }
        return null;
    }

}
